﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spanner
{
    public static class UIKoExtensionMethods
    {
        public static Html KoVisible(this Html html, Expr<bool> e) {
            return html.DataBind("visible", e);
        }

        public static Html KoText(this Html html, Expr<string> e) {
            return html.DataBind("text", e);
        }

        public static Html KoText(this Html html, Expr<int> e) {
            return html.DataBind("text", e);
        }

        public static Html KoText(this Html html, Expr<double> e) {
            return html.DataBind("text", e);
        }

        public static Html KoHtml(this Html html, Expr<string> e) {
            return html.DataBind("html", e);
        }

        public static Html KoCss(this Html html, Expr<string> dynamicClass)
        {
            return html.DataBind("css", dynamicClass);
        }

        public static Html KoCss(this Html html, params CssClassCondition[] classConditions)
        {
            if (classConditions == null) return html;
            return html.DataBind("css", new FmtBraces(classConditions));
        }

        public static Html KoStyle(this Html html, params CssStyleValue[] styleValues)
        {
            if (styleValues == null) return html;
            return html.DataBind("style", new FmtBraces(styleValues));
        }

        public static Html KoAttr(this Html html, params AttrValue[] attrValues)
        {
            if (attrValues == null) return html;
            return html.DataBind("attr", new FmtBraces(attrValues));
        }

        public static Html KoForEach<T>(this Html html, Expr<T[]> xs, Func<Param<T>, Html> f)
        {
            var x = html.DataBind("foreach", xs)
                        .WithChildren(new UI.KoForEachHtml<T> { F = f, UseCommentForm = false });
            return x;
        }

        public static Html KoIf(this Html html, Expr<bool> e) {
            return html.DataBind("if", e);
        }

        public static Html KoIfTruthy<T>(this Html html, Expr<T> e) {
            return html.DataBind<T>("if", e);
        }

        public static Html KoIfNot(this Html html, Expr<bool> e) {
            return html.DataBind("ifnot", e);
        }

        public static Html KoIfFalsy<T>(this Html html, Expr<T> e) {
            return html.DataBind<T>("ifnot", e);
        }

        // XXX 'with' -- do we want this binding?
        // I'm going to say no: everything Spanner does depends on the view model
        // being the binding context (or at the bottom of some 'forall' nesting).

        public static Html KoClick(this Html html, Act a) {
            return html.DataBind("click", UI.Proc(a));
        }

        public static Html KoClick(this Html html, Expr<Fn<Act>> a) {
            return html.DataBind("click", a);
        }

        public static Html KoClick(this Html html, Expr<Fn<bool>> a) {
            return html.DataBind("click", a);
        }

        public static Html KoClick<T>(this Html html, Expr<Fn<DummyType, T, Act>> a) {
            return html.DataBind("click", a);
        }

        public static Html KoClick<T>(this Html html, Expr<Fn<DummyType, T, bool>> a) {
            return html.DataBind("click", a);
        }

        public static Html KoEvent(this Html html, params DomEventHandler[] eventProcs)
        {
            if (eventProcs == null) return html;
            return html.DataBind("event", new FmtBraces(eventProcs));
        }

        public static Html KoBubble(this Html html, string domEventName, Expr<bool> e)
        {
            return html.DataBind<bool>(domEventName.ToLower() + "Bubble", e ?? false);
        }

        public static Html KoNoBubble(this Html html, string domEventName)
        {
            return html.DataBind<bool>(domEventName.ToLower() + "Bubble", false);
        }

        public static Html KoSubmit(this Html html, Act a) {
            return html.DataBind("submit", UI.Proc(a));
        }

        public static Html KoSubmit(this Html html, Expr<Fn<Act>> a) {
            return html.DataBind("submit", a);
        }

        public static Html KoEnable(this Html html, Expr<bool> e) {
            return html.DataBind("enable", e);
        }

        // A synonym for KoEnable.
        public static Html KoEnabled(this Html html, Expr<bool> e) {
            return html.DataBind("enable", e);
        }

        public static Html KoDisable(this Html html, Expr<bool> e) {
            return html.DataBind("disable", e);
        }

        // A synonym for KoDisable.
        public static Html KoDisabled(this Html html, Expr<bool> e) {
            return html.DataBind("disable", e);
        }

        public static Html KoValue<T>(this Html html, ObsVar<T> x) {
            return html.DataBind("value", UI.Ref(x));
        }

        public static Html KoValue<T>(this Html html, Expr<ObsVarRef<T>> r) {
            return html.DataBind("value", r);
        }

        public static Html KoValueUpdate(this Html html, KoValueUpdateOn eventName)
        {
            return html.DataBind<string>("valueUpdate", eventName.ToString().ToLower());
        }

        public static Html KoHasFocus(this Html html, Expr<bool> e) {
            return html.DataBind("hasfocus", e);
        }

        public static Html KoChecked(this Html html, Expr<ObsVarRef<bool>> r) {
            return html.DataBind("checked", r);
        }

        public static Html KoChecked(this Html html, ObsVar<bool> r) {
            return html.DataBind("checked", UI.Ref(r));
        }

        public static Html KoOptions<T>(this Html html, Expr<T[]>options) {
            return html.DataBind<T[]>("options", options);
        }

        public static Html KoOptionsText(this Html html, string fieldName) {
            return html.DataBind<string>("optionsText", fieldName);
        }

        public static Html KoOptionsText<T>(this Html html, Expr<Fn<T, string>> fn) {
            return html.DataBind<Fn<T, string>>("optionsText", fn);
        }

        public static Html KoOptionsCaption(this Html html, string caption) {
            return html.DataBind<string>("optionsCaption", caption);
        }

        public static Html KoOptionsValue(this Html html, string optionsValue) {
            return html.DataBind<string>("optionsValue", optionsValue);
        }

        public static Html KoSelectedOptions<T>(this Html html, ObsVar<T[]> selectedOptions) {
            return html.DataBind<ObsVarRef<T[]>>("selectedOptions", UI.Ref(selectedOptions));
        }

        public static Html KoUniqueName(this Html html, Expr<bool> cond = null) {
            return html.DataBind("uniqueName", cond ?? true);
        }

        public static Html KoTemplate(this Html html, Expr<TemplateModel> args)
        {
            return html.DataBind("template", UI.JSExpr<TemplateModel>("spanner.templateArgs(#)", args));
        }

    }
}
